home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume6 / cpic < prev    next >
Encoding:
Text File  |  1989-03-21  |  28.4 KB  |  1,340 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v06i075: cpic --- yet another troff preprocessor
  4. Reply-To: tcjones@watdragon.waterloo.edu (speedboat jones)
  5. Distribution: world
  6. Organization: U. of Waterloo, Ontario
  7.  
  8. Posting-number: Volume 6, Issue 75
  9. Submitted-by: tcjones@watdragon.waterloo.edu (speedboat jones)
  10. Archive-name: cpic
  11.  
  12.  
  13.  
  14. cpic --- troff preprocessor producing pic(1) output to draw some simple graphs
  15.          and diagrams.
  16.  
  17.  
  18. This is a little language that lets you draw simple graphs (the nodes
  19. and edges type) in pic. There's very little to it and it produces nice
  20. pictures. The best way to see what happens is to make it and run the
  21. Example file through cpic and pic and eqn and troff -ms and compare what
  22. comes out to what went in.  Good luck.
  23.  
  24. Terry Jones
  25.  
  26.     Department Of Computer Science,  University Of Waterloo
  27.     Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
  28.     UUCP:                    ...!watmath!watdragon!tcjones
  29.     CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
  30.     BITNET:                  tcjones@WATER.bitnet
  31.     Canadian domain:         tcjones@dragon.uwaterloo.ca
  32.  
  33.  
  34.  
  35. #! /bin/sh
  36. # This is a shell archive.  Remove anything before this line, then unpack
  37. # it by saving it into a file and typing "sh file".  To overwrite existing
  38. # files, type "sh file -c".  You can also feed this as standard input via
  39. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  40. # will see the following message at the end:
  41. #        "End of archive 1 (of 1)."
  42. # Contents:  cpic cpic/Example cpic/README cpic/cpic.c cpic/cpic.h
  43. # Wrapped by tcjones@watdragon on Wed Mar 15 14:03:58 1989
  44. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  45. if test ! -d 'cpic' ; then
  46.     echo shar: Creating directory \"'cpic'\"
  47.     mkdir 'cpic'
  48. fi
  49. if test -f 'cpic/Example' -a "${1}" != "-c" ; then 
  50.   echo shar: Will not clobber existing file \"'cpic/Example'\"
  51. else
  52. echo shar: Extracting \"'cpic/Example'\" \(4965 characters\)
  53. sed "s/^X//" >'cpic/Example' <<'END_OF_FILE'
  54. X.LP
  55. X.EQ
  56. delim $$
  57. X.EN
  58. X
  59. X.TL
  60. CPIC
  61. X
  62. X.NH 1
  63. Pictures vs Figures
  64. X
  65. X.PP
  66. XFor the purposes of this discussion a picture will be thought of as containing
  67. some positive number of figures. The figures are drawn side by side.
  68. X
  69. X.NH 1
  70. Delimiters and Arguments
  71. X
  72. X.PP
  73. Delimit the picture with .CPS and .CPE (Charlie Pic Start/End).  The
  74. X\&.CPS line can take two real arguments, they are the radius of the
  75. circle on which the vertices of the figures are put, and the radius of
  76. the actual vertices. If only one argument is given it is taken as the
  77. radius of the figures. You can change the default values to suit
  78. yourself by doing obvious things to cpic.h. The default values are 0.4
  79. for the figure radius and 0.02 for the vertex radius.
  80. X
  81. X.NH 1
  82. How Many Figures to a Picture
  83. X
  84. X.PP
  85. You can have as many as you like (in theory). You will need to adjust 
  86. the default figure radius if you require alot of figures or if you have
  87. wide labels on your figures.
  88. The first number after the .CPS line tells how many individual figures 
  89. there will be in this picture.
  90. X
  91. X.NH 1
  92. Defining a Figure
  93. X
  94. X.PP
  95. XEach figure in the picture is specified as follows:
  96. firstly, give the number of vertices that will be in this figure,
  97. and then give its edge list.
  98. X
  99. X.NH 2
  100. The Figure's Vertex Count
  101. X
  102. X.PP
  103. Typically you will just want to simply say how many vertices are to be in the
  104. next figure of this picture. This is done as one would expect, by giving the 
  105. count alone on a line. It is also possible to define a label for each figure.
  106. The label should be given enclosed in double quotes (") and will be placed to
  107. the left of the figure in question. Cpic will make a primitive attempt to
  108. estimate the width of the label. If the spacing is not correct the the width
  109. may also be given as a third parameter.
  110. X
  111. An example is
  112. X.br
  113. X8 "Octahedron" 1.0
  114. X.br
  115. which specifies a figure on eight vertices, labelled with the string 
  116. X"Octahedron" centred in a field one inch wide. Cpic should be able to
  117. guesstimate the appropriate width for simple labels such as this.
  118. X
  119. X.NH 2
  120. A Figure's Edge List
  121. X
  122. X.PP
  123. XEdges are specified as a b c, meaning vertex a should be joined
  124. to vertex b with a multiplicity of c. If c is omitted it defaults to 1.
  125. c must be less than or equal to 3. The edge list should immediately 
  126. follow the vertex count.
  127. X
  128. The vertices will be numbered from 1 upwards. Vertex 1 will always be 
  129. located on the same horizontal level as the centre of the figure, and
  130. to the right of the centre. The numbering continues consecutively
  131. anti-clockwise around the circumference. I should have added a feature
  132. to allow for an initial rotation instead of insisting that the first 
  133. vertex be at 0 degrees. This numbering is internal and should not be confused
  134. with labels that might one day appear on vertices when the page is printed.
  135. X
  136. X.NH 1
  137. Labelling the Entire Picture
  138. X
  139. X.PP
  140. This is most comfortably accomplished by giving the label after the .CPE.
  141. X
  142. X.NH 1
  143. Comments etc.
  144. X
  145. X.PP
  146. Comments are allowed - a comment line is one that starts with a #. 
  147. Blank lines are also ignored. The entire cpic specification will be
  148. output (commented out) within the produced pic.
  149. X
  150. X
  151. X.NH 1
  152. Invocation
  153. X
  154. X.PP
  155. Cpic can be run as a filter or may take file name arguments (but not
  156. both simultaneously). Output may be sent to a file or (by default) to stdout.
  157. Use -o <filename> to write output to a file. This will not overwrite an
  158. existing file though, for that use -O <filename>.
  159. The input specification will be given (commented) in the output pic.
  160. X.br
  161. The following are valid.  
  162. X
  163. X.br
  164. X.I
  165. cpic fred.in > fred.out
  166. X.br
  167. cpic -o fred.out fred.in 
  168. X.br
  169. cat fred.in | cpic > fred.out
  170. X.br
  171. cat fred.in | cpic | pic | tbl etc etc etc...
  172. X.br
  173. X.R
  174. X
  175. X.NH 1
  176. Notes
  177. X
  178. X.PP
  179. All measurements should be given in inches and as floating point
  180. numbers, there is no need to specify the trailing "i" for inches \- the
  181. world will probably end if you do.  The generated pic could be tidied
  182. considerably, and I should add the ability to label vertices and an
  183. option to give an initial rotation for each figure.  Let me know if you
  184. want any of this done.
  185. X
  186. X.NH 1
  187. XExample
  188. X
  189. X.PP
  190. You get the idea. Here is an example.
  191. X
  192. X.CPS 0.3
  193. X# use figure radius of 0.3 inches.
  194. X
  195. X# six figures in this diagram (six things on this line).
  196. X6 
  197. X
  198. X# the first has 4 vertices.
  199. X4 "A:"
  200. X1 2 3
  201. X2 3 2
  202. X3 4
  203. X
  204. X# one with 16 vertices...
  205. X16 "B:"
  206. X2 3 2
  207. X4 7 1
  208. X8 11 3
  209. X5 9
  210. X1 7
  211. X4 12
  212. X13 14
  213. X
  214. X# the third.
  215. X5 "C:"
  216. X1 3
  217. X3 5
  218. X5 2
  219. X2 4
  220. X4 1
  221. X
  222. X# the fourth.
  223. X2 "D:"
  224. X1 2 3
  225. X
  226. X# the fifth.
  227. X8 "E:"
  228. X1 2 2
  229. X2 3
  230. X5 2 3
  231. X6 1 1
  232. X2 4 2
  233. X3 4 
  234. X4 5 2
  235. X5 6 2
  236. X6 7
  237. X7 8
  238. X
  239. X# the sixth.
  240. X6 "F:"
  241. X1 2 1
  242. X4 5 2
  243. X5 6 3
  244. X.CPE
  245. X
  246. X.ce
  247. XFig 3: Six pretty little figures are shown above.
  248. X
  249. X
  250. X
  251. The vortex...
  252. X
  253. X.CPS
  254. X1
  255. X16 "$ sigma pi 2x sub i$" 1.0
  256. X# tell cpic how long the label is as it doesn't understand eqn.
  257. X
  258. X1 8
  259. X8 15
  260. X15 6
  261. X6 13
  262. X13 4
  263. X4 11
  264. X11 2
  265. X2 9
  266. X9 16
  267. X16 7
  268. X7 14
  269. X14 5
  270. X5 12
  271. X12 3
  272. X3 10
  273. X10 1
  274. X.CPE
  275. X.ce 
  276. XFig 900: The vortex.
  277. X
  278. X.PP
  279. Here are some that are not in the default size.
  280. X.CPS 0.5 .05
  281. X3
  282. X
  283. X3 "Three pictures:"
  284. X2 3 2
  285. X2 1 2
  286. X
  287. X3
  288. X1 2 2
  289. X1 3 2
  290. X
  291. X3
  292. X3 1 2
  293. X3 2 2
  294. X.CPE
  295. X.ce
  296. Three lovely little babies.
  297. X
  298. X.br
  299. Goodbye
  300. END_OF_FILE
  301. if test 4965 -ne `wc -c <'cpic/Example'`; then
  302.     echo shar: \"'cpic/Example'\" unpacked with wrong size!
  303. fi
  304. # end of 'cpic/Example'
  305. fi
  306. if test -f 'cpic/README' -a "${1}" != "-c" ; then 
  307.   echo shar: Will not clobber existing file \"'cpic/README'\"
  308. else
  309. echo shar: Extracting \"'cpic/README'\" \(788 characters\)
  310. sed "s/^X//" >'cpic/README' <<'END_OF_FILE'
  311. X
  312. cpic --- troff preprocessor producing pic(1) output to draw some simple graphs
  313. X         and diagrams.
  314. X
  315. X
  316. This is a little language that lets you draw simple graphs (the nodes and 
  317. edges type) in pic. There's very little to it and it produces nice 
  318. pictures. The best way to see what happens is to compile it and
  319. run the Example file through cpic and then pic and eqn and troff -ms and
  320. have a look at what comes out. Good luck.
  321. X
  322. Terry Jones
  323. X
  324. X    Department Of Computer Science,  University Of Waterloo
  325. X    Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
  326. X    UUCP:                    ...!watmath!watdragon!tcjones
  327. X    CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
  328. X    BITNET:                  tcjones@WATER.bitnet
  329. X    Canadian domain:         tcjones@dragon.uwaterloo.ca
  330. END_OF_FILE
  331. if test 788 -ne `wc -c <'cpic/README'`; then
  332.     echo shar: \"'cpic/README'\" unpacked with wrong size!
  333. fi
  334. # end of 'cpic/README'
  335. fi
  336. if test -f 'cpic/cpic.c' -a "${1}" != "-c" ; then 
  337.   echo shar: Will not clobber existing file \"'cpic/cpic.c'\"
  338. else
  339. echo shar: Extracting \"'cpic/cpic.c'\" \(17631 characters\)
  340. sed "s/^X//" >'cpic/cpic.c' <<'END_OF_FILE'
  341. X/*
  342. X *  Cpic.c --- produce pic output for graphs in which all vertices lie on a
  343. X *  circle and edge multiplicity is <= 3.
  344. X *
  345. X *  Terry Jones  (tcjones@watdragon)
  346. X */
  347. X
  348. X#include <stdio.h>
  349. X#include <sys/types.h>
  350. X#include <sys/stat.h>
  351. X#include <errno.h>
  352. X#include <signal.h>
  353. X#include <math.h>
  354. X#include "cpic.h"
  355. X
  356. char *this_file;
  357. XFILE *in_fp;
  358. XFILE *out_fp;
  359. char *myname;
  360. int line_number = 0;
  361. int found_line = 0;
  362. edge_list *avail_edges = NULL;
  363. picture *avail_pics = NULL;
  364. X
  365. main(argc, argv)
  366. int argc;
  367. char **argv;
  368. X{
  369. X    extern char *getenv();
  370. X    FILE *open_file();
  371. X    extern void clean_up();
  372. X    int std_in = 0;
  373. X
  374. X    myname=*argv;
  375. X    handle_signals();
  376. X
  377. X    set_io(argv, &argc, &std_in);
  378. X
  379. X    if (std_in){
  380. X        in_fp = stdin;
  381. X        this_file = "(standard input)";
  382. X        do_file(stdin, out_fp);
  383. X    }
  384. X    else{
  385. X        if (out_fp != stdout){
  386. X            argc -= 2;
  387. X            argv += 2;
  388. X        }
  389. X        while (--argc){
  390. X            this_file = *++argv;
  391. X            in_fp = open_file(this_file,"r",0);
  392. X            if (in_fp == NULL) continue;
  393. X            do_file(in_fp, out_fp);
  394. X        }
  395. X    }
  396. X    fclose(out_fp);
  397. X    exit(0);
  398. X}
  399. X
  400. X
  401. set_io(c, n, std_in)
  402. char **c;
  403. int *n;
  404. int *std_in;
  405. X{
  406. X    switch (*n - 1){
  407. X
  408. X        case 0: {
  409. X            *std_in = 1;
  410. X            out_fp = stdout;
  411. X            break;
  412. X        }
  413. X
  414. X        case 1: {
  415. X            if (!strcmp(c[1],"-h") || !strcmp(c[1],"-help")) help();
  416. X            out_fp = stdout;
  417. X            break;
  418. X        }
  419. X
  420. X        default: {
  421. X            if (!strcmp(c[1],"-o")){
  422. X                out_fp = open_file(c[2], "w", 0);  /* open w/o clobbering. */
  423. X
  424. X                if (*n == 3){
  425. X                    *std_in = 1;
  426. X                }
  427. X            }
  428. X
  429. X            else if (!strcmp(c[1],"-O")){
  430. X                out_fp = open_file(c[2], "w", 1); /* open & clobber. */
  431. X
  432. X                if (*n == 3){
  433. X                    *std_in = 1; /* All arguments are used up. */
  434. X                }
  435. X            }
  436. X
  437. X            else out_fp = stdout;
  438. X            break;
  439. X        }
  440. X    }
  441. X}
  442. X        
  443. X
  444. help()
  445. X{
  446. X    fprintf(stderr,"Usage: %s [-[oO] outfile] [infiles...]\n", myname);
  447. X    exit(0);
  448. X}
  449. X
  450. X
  451. handle_signals()
  452. X{
  453. X    if (signal(SIGINT,SIG_IGN)!=SIG_IGN){
  454. X        signal(SIGINT,clean_up);
  455. X    }
  456. X}
  457. X
  458. void
  459. clean_up()
  460. X{
  461. X    fprintf(stderr,"\nInterrupt...\n");
  462. X    goodbye();
  463. X}
  464. X
  465. do_file(in_f, out_f)
  466. XFILE *in_f;
  467. XFILE *out_f;
  468. X{
  469. X    extern picture *begin_picture();
  470. X    extern char *get_quoted_name();
  471. X    char *getline();
  472. X    char line[MAX];
  473. X    picture_list pics;
  474. X    picture *curr_pic = NULL;
  475. X    char *pic_title = NULL;
  476. X    int pics_this_list = 0;
  477. X    double picr;
  478. X    double ptr;
  479. X
  480. X    pics.pic = NULL;
  481. X
  482. X    while ( GETLINE ){
  483. X
  484. X        line_number++;
  485. X
  486. X        /* A line we are not interested in, print it and go on. */
  487. X        if (strlen(line) < 4 || strncmp(line, ".CPS", 4) != 0){
  488. X            fprintf(out_f, "%s\n", line);
  489. X            continue;
  490. X        }
  491. X
  492. X
  493. X        /* A line we are interested in. */
  494. X        /* This line will have format ".CPS [pic_radius] [point_radius]" */
  495. X
  496. X        switch (sscanf(line,".CPS %f %f", &picr, &ptr)){
  497. X
  498. X            case EOF: {
  499. X                /* Could not match, but tried. */
  500. X                picr = PIC_RADIUS;
  501. X                ptr = POINT_RADIUS;
  502. X                break;
  503. X            }
  504. X
  505. X            case 1: {
  506. X                /* Got picr from the sscanf */
  507. X                ptr = POINT_RADIUS;
  508. X                break;
  509. X            }
  510. X
  511. X            case 2: {
  512. X                break;
  513. X            }
  514. X
  515. X            default: {
  516. X                fprintf(stderr,
  517. X                    "%s: .CPS line syntax is \".CPS [picture radius [", myname);
  518. X                fprintf(stderr,
  519. X                    "point radius]]\". Both are taken to be in inches and\n");
  520. X                fprintf(stderr,
  521. X                    "default to %.2f and %.2f if omitted. (Line=%d, File=%s)\n",
  522. X                    PIC_RADIUS, POINT_RADIUS, line_number, this_file);
  523. X
  524. X                goodbye();
  525. X                break;
  526. X            }
  527. X
  528. X        }
  529. X
  530. X        /* Start pic processing. */
  531. X        /* fprintf(out_f, ".PS\n#%s\n", line); */
  532. X        fprintf(out_f, ".PS\n");
  533. X
  534. X
  535. X        if ( ! GETLINE ) goodbye();
  536. X        line_number++;
  537. X
  538. X        while (allwhite(line) || iscomment(line)){
  539. X            /* fprintf(out_f,"%s\n",line); */
  540. X            if ( ! GETLINE ) goodbye();
  541. X            line_number++;
  542. X        }
  543. X
  544. X        /* Get the number of pictures that will be on this line. */
  545. X        if (sscanf(line, "%d", &pics_this_list) != 1) goodbye();
  546. X        found_line = line_number;
  547. X
  548. X        pic_title = get_quoted_name(line);
  549. X        begin_picture_list(&pics, pics_this_list, pic_title);
  550. X
  551. X        /* Used to print out the definition commented out, but don't worry. */
  552. X        /* fprintf(out_f, "#%s\n", line); */
  553. X
  554. X        while ( GETLINE ){
  555. X
  556. X            int n1, n2, n3;
  557. X            int pictures_done = 0;
  558. X
  559. X            line_number++;
  560. X
  561. X            /* skip blank and comment lines */
  562. X            while (allwhite(line) || iscomment(line)){
  563. X                /* fprintf(out_f,"%s\n", line); */
  564. X                if ( ! GETLINE ) goodbye();
  565. X                line_number++;
  566. X            }
  567. X
  568. X            /* Now we have a non-blank, non-comment line. */
  569. X            /* Don't worry about echoing it. */
  570. X            /* fprintf(out_f, "#%s\n", line); */
  571. X
  572. X            switch(sscanf(line, "%d %d %d", &n1, &n2, &n3)){
  573. X
  574. X                /* The number of vertices that this picture will be on. */
  575. X                case 1: {
  576. X
  577. X                    extern char *get_quoted_name();
  578. X                    extern double get_width();
  579. X
  580. X                    double width = get_width(line);
  581. X                    char *pic_name = get_quoted_name(line);
  582. X
  583. X                    curr_pic = 
  584. X                        begin_picture(&pics, curr_pic, n1, pic_name, width);
  585. X                    break;
  586. X                }
  587. X
  588. X
  589. X                /* Two vertices which are to be joined (once). */
  590. X                case 2: {
  591. X                    add_edges(curr_pic, n1, n2, 1);
  592. X                    break;
  593. X                }
  594. X
  595. X                /* Two vertices to be joined and the edge multiplicity */
  596. X                case 3: {
  597. X                    add_edges(curr_pic, n1, n2, n3);
  598. X                    break;
  599. X                }
  600. X
  601. X                default: {
  602. X                    if (strlen(line) < 4 || strncmp(line, ".CPE", 4) != 0){
  603. X                        fprintf(stderr,"Whoops! bad input \n");
  604. X                        
  605. X                        goodbye();
  606. X                    }
  607. X
  608. X                    end_picture(&pics, picr, ptr, out_f);
  609. X                    pictures_done = 1;
  610. X                    break;
  611. X                }
  612. X            }
  613. X
  614. X        if (pictures_done) break;
  615. X        }
  616. X    }
  617. X    fclose(in_f);
  618. X}
  619. X
  620. begin_picture_list(pl, max_vertices, pic_title)
  621. picture_list *pl;
  622. int max_vertices;
  623. char *pic_title;
  624. X{
  625. X    if (pl->pic != NULL) free_picture_list(pl);
  626. X    pl->pic_limit = max_vertices;
  627. X    pl->pics_in_list = 0;
  628. X    pl->total_label_width = 0.0;
  629. X    strcpy(pl->pic_title, pic_title);
  630. X    pl->pic = NULL;
  631. X}
  632. X
  633. X
  634. picture *
  635. begin_picture(pl, cp, vertices, pic_name, width)
  636. picture_list *pl;
  637. picture *cp;
  638. int vertices;
  639. char *pic_name;
  640. double width;
  641. X{
  642. X    extern picture *new_picture();
  643. X
  644. X    if (pl->pic_limit == pl->pics_in_list){
  645. X        fprintf(stderr,"%s: %d pictures promised on line %d of file %s,\n", 
  646. X            myname, pl->pic_limit, found_line, this_file);
  647. X        
  648. X        fprintf(stderr,"but the picture beginning line %d exceeds this!\n",
  649. X            line_number);
  650. X        goodbye();
  651. X    }
  652. X
  653. X    if (vertices == 0){
  654. X        fprintf(stderr,
  655. X            "%s: A graph with 0 vertices? Interesting. Line=%d, File=%s.\n",
  656. X            myname, line_number, this_file);
  657. X        goodbye();
  658. X    }
  659. X
  660. X    if (width < 0.0){
  661. X        fprintf(stderr,
  662. X            "%s: A label with negative width? Interesting. Line=%d, File=%s.\n",
  663. X            myname, line_number, this_file);
  664. X        goodbye();
  665. X    }
  666. X
  667. X
  668. X    pl->pics_in_list++;
  669. X
  670. X    if (pl->pic == NULL){
  671. X        pl->pic = cp = new_picture();
  672. X    }
  673. X    else{
  674. X        cp->next_pic = new_picture();
  675. X        cp = cp->next_pic;
  676. X    }
  677. X
  678. X
  679. X    /* Try to estimate the label's width. */
  680. X    /* Actual string to be printed does not include the 2 "'s */
  681. X    if (pic_name && width == 0.0) 
  682. X        width = CHAR_WIDTH * (double)(strlen(pic_name) - 2);
  683. X
  684. X    /* Add to the total amount of label space we have seen for this pic. */
  685. X    if (pic_name) 
  686. X        pl->total_label_width += width;
  687. X
  688. X    cp->vertices = vertices;
  689. X    strcpy(cp->fig_name, pic_name);
  690. X    cp->label_width = width;
  691. X    return(cp);
  692. X}
  693. X
  694. X
  695. add_edges(cp, v1, v2, multiplicity)
  696. picture *cp;
  697. int v1;
  698. int v2;
  699. int multiplicity;
  700. X{
  701. X    extern edge_list *new_edge_list();
  702. X    edge_list *temp_e_list;
  703. X
  704. X    if (cp == NULL){
  705. X        fprintf(stderr,"%s: Oops! you tried to define edges before saying\n",
  706. X            myname);
  707. X        fprintf(stderr,
  708. X            "how many vertices there were going to be. Line=%d, File=%s\n",
  709. X            line_number, this_file);
  710. X        goodbye();
  711. X    }
  712. X
  713. X    if (v1 < 1 || v2 < 1 || v1 > cp->vertices || v2 > cp->vertices){
  714. X        fprintf(stderr,
  715. X            "%s: Vertex index outside legal range on line %d, in file %s.\n", 
  716. X            myname, line_number, this_file);
  717. X        goodbye();
  718. X    }
  719. X
  720. X    if (multiplicity < 1 || multiplicity > 3){
  721. X        fprintf(stderr,
  722. X            "%s: Illegal edge multiplicity of %d give on line %d in file %s.\n",
  723. X            myname, multiplicity, line_number, this_file);
  724. X        goodbye();
  725. X    }
  726. X
  727. X    if (v1 == v2){
  728. X        fprintf(stderr,
  729. X"%s: Self loops not supported - edge %d,%d ignored on line %d in file %s.\n",
  730. X            myname, v1, v1, line_number, this_file);
  731. X        return;
  732. X    }
  733. X
  734. X    temp_e_list = new_edge_list();
  735. X
  736. X    temp_e_list->v1 = v1;
  737. X    temp_e_list->v2 = v2;
  738. X    temp_e_list->times = multiplicity;
  739. X
  740. X    temp_e_list->next_edge = cp->e_list;
  741. X    cp->e_list = temp_e_list;
  742. X}
  743. X
  744. XFILE *
  745. open_file(s,mode,flag)
  746. char *s;
  747. char *mode;
  748. int flag;
  749. X{
  750. X    /* 
  751. X     * fopen() the file whose name is "s", exit on error.
  752. X     * flag is clobber mode for "w". 1 = clobber existing file.
  753. X     *
  754. X     */
  755. X
  756. X
  757. X    FILE *fp, *fopen();
  758. X    struct stat buf;
  759. X
  760. X    if (strcmp(mode,"w") == 0 && flag != 1 && stat(s, &buf) != -1){
  761. X        fprintf(stderr,
  762. X            "%s: file \"%s\" already exists! (Use -O to overwrite.)\n", 
  763. X            myname, s);
  764. X        exit(1);
  765. X    }
  766. X
  767. X    if (!(fp=fopen(s,mode))){
  768. X        fprintf(stderr,"%s: could not open %s (ignored).\n", myname, s);
  769. X    }
  770. X
  771. X    return(fp);
  772. X}
  773. X
  774. X
  775. X
  776. int
  777. file_exists(s)
  778. char *s;
  779. X{
  780. X    /* 
  781. X     * return 1 if the file s exists, 0 if not.
  782. X     * This is silly - I should have used access(). Didn't know about it.
  783. X     *
  784. X     */
  785. X
  786. X
  787. X    extern int errno;
  788. X    struct stat buf;
  789. X    int status;
  790. X
  791. X    status = stat(s, &buf);
  792. X
  793. X    if (status == 0){
  794. X        return(1);
  795. X    }
  796. X    else if (status == -1 && errno == ENOENT){
  797. X        return(0);
  798. X    }
  799. X    else{
  800. X        fprintf(stderr,"file_exists: stat failed, errno=%d\n", errno);
  801. X        perror("stat");
  802. X        exit(1);
  803. X    }
  804. X}
  805. X
  806. char *
  807. getline(fp,max,where)
  808. XFILE *fp;
  809. int max;
  810. char *where;
  811. X{
  812. X    /* returns null terminated line in "where" and NULL on EOF or error */
  813. X    /* essentially does what gets() does, except for any open FILE * */
  814. X
  815. X    extern char* index();
  816. X    char *fred;
  817. X    
  818. X    if ((fred=fgets(where,max,fp))){
  819. X        char *tmp;
  820. X        if (!(tmp=index(where,'\n'))){
  821. X            printf("getline: Line with no newline!\n");
  822. X            exit(1);
  823. X        }
  824. X        *tmp='\0';
  825. X    }
  826. X    return(fred);
  827. X}
  828. X
  829. X
  830. int 
  831. allwhite(s)
  832. char *s;
  833. X{
  834. X    /*
  835. X     * Return 1 if the char array s is all white space, or empty.
  836. X     *
  837. X     */
  838. X
  839. X    if (!strlen(s)) return(1);
  840. X
  841. X    while (*s){
  842. X        if (*s != ' ' && *s != '\t'){
  843. X            return(0);
  844. X        }
  845. X        s++;
  846. X    }
  847. X    return(1);
  848. X}
  849. X
  850. X
  851. picture *
  852. new_picture()
  853. X{
  854. X    picture *temp;
  855. X
  856. X    if (avail_pics == NULL){
  857. X        if ((temp = (picture *)malloc((unsigned long)sizeof(picture))) == NULL){
  858. X            fprintf(stderr,"Could not malloc! giving up.\n");
  859. X            exit(1);
  860. X        }
  861. X    }
  862. X    else{
  863. X        temp = avail_pics;
  864. X        avail_pics = avail_pics->next_pic;
  865. X    }
  866. X
  867. X    temp->vertices = 0;
  868. X    temp->fig_name[0] = '\0';
  869. X    temp->label_width = 0.0;
  870. X    temp->e_list = NULL;
  871. X    temp->next_pic = NULL;
  872. X    return(temp);
  873. X}
  874. X
  875. edge_list *
  876. new_edge_list()
  877. X{
  878. X    edge_list *temp;
  879. X
  880. X    if (avail_edges == NULL){
  881. X        if ((temp = 
  882. X            (edge_list *)malloc((unsigned long)sizeof(edge_list))) == NULL){
  883. X
  884. X            fprintf(stderr,"Could not malloc! giving up.\n");
  885. X            exit(1);
  886. X        }
  887. X    }
  888. X    else{
  889. X        temp = avail_edges;
  890. X        avail_edges = avail_edges->next_edge;
  891. X    }
  892. X
  893. X    temp->v1 = temp->v2 = temp->times = 0;
  894. X    temp->next_edge = NULL;
  895. X    return(temp);
  896. X}
  897. X
  898. goodbye()
  899. X{
  900. X    fflush(stderr);
  901. X    fclose(in_fp);
  902. X    fclose(out_fp);
  903. X    fprintf(stderr,"%s: Execution aborted on line %d in file %s.\n",
  904. X        myname, line_number, this_file);
  905. X    exit(1);
  906. X}
  907. X
  908. X
  909. X
  910. free_picture_list(pl)
  911. picture_list *pl;
  912. X/* This does not seem to free anything! Is it wrong?  TERRY! */
  913. X{
  914. X    picture *this_pic = pl->pic;
  915. X    edge_list *this_e_list;
  916. X
  917. X    if (this_pic == NULL) return;
  918. X
  919. X    while (this_pic->next_pic != NULL){
  920. X        if (this_pic->e_list != NULL){
  921. X            this_e_list = this_pic->e_list;
  922. X            while (this_e_list->next_edge != NULL){
  923. X                this_e_list = this_e_list->next_edge;
  924. X            }
  925. X
  926. X            this_e_list->next_edge = avail_edges;
  927. X            avail_edges = this_pic->e_list;
  928. X        }
  929. X
  930. X        this_pic = this_pic->next_pic;
  931. X    }
  932. X    this_pic->next_pic = avail_pics;
  933. X    avail_pics = pl->pic;
  934. X}
  935. X
  936. X
  937. end_picture(pl, picr, ptr, f)
  938. picture_list *pl;
  939. double picr;
  940. double ptr;
  941. XFILE *f;
  942. X{
  943. X    /* Produce pic output for each of the pictures in the picture list. */
  944. X
  945. X    /* 
  946. X     * Will need to do some looking at the list to determine the width
  947. X     * and other things like that - saving on recomputation of sins etc.
  948. X     * but for now just be dumb so we can get some output!
  949. X     */
  950. X
  951. X    picture *p = pl->pic;
  952. X    int rad_count = 1;
  953. X    int sep_count = 1;
  954. X    double sep;
  955. X    double pic_y;
  956. X    double arc_rad;
  957. X    double x_adjust = BOUNDARY;
  958. X
  959. X    if (pl->pic_limit != pl->pics_in_list){
  960. X        fprintf(stderr,
  961. X            "%s: You promised %d graphs but gave %d. (Line %d, File %s)\n",
  962. X            myname, pl->pic_limit, pl->pics_in_list, line_number, this_file);
  963. X        goodbye();
  964. X    }
  965. X
  966. X    /* Calculate inter-picture separator. */
  967. X    sep = (PAGE_WIDTH - 
  968. X           (2.0 * (double)(pl->pic_limit) * picr) - pl->total_label_width
  969. X          ) / (double)(pl->pic_limit + 1.0);
  970. X
  971. X    /* Calculate height of figure centres. */
  972. X    pic_y = picr + BOUNDARY + (pl->pic_title[0] ? TITLE_SEP : 0.0);
  973. X
  974. X    /* 
  975. X     * debug - point of reference.
  976. X     * fprintf(f,"circle rad 0.1i at (0i,%.2fi) #invisible\n", picr + sep);
  977. X     */
  978. X
  979. X    while (p != NULL){
  980. X        /* process each picture in turn. */
  981. X
  982. X        char centre[15];
  983. X
  984. X        x_adjust += p->label_width; /* Will be 0.0 if there is no label. */
  985. X        sprintf(centre,"(%.2fi,%.2fi)", 
  986. X            rad_count*picr + sep_count*sep + x_adjust, pic_y);
  987. X        
  988. X        produce_pic(p, centre, picr, ptr, f);
  989. X
  990. X        rad_count += 2;
  991. X        sep_count++;
  992. X        p = p->next_pic;
  993. X    }
  994. X
  995. X    /* 
  996. X     * DISABLED - use .ce in plain troff to get the title for the picture
  997. X     * Do the title for the whole picture.
  998. X     * if (pl->pic_title[0]){
  999. X     *    fprintf(f, "%s at (%.2fi,%2fi)\n", pl->pic_title, 
  1000. X     *
  1001. X     *        either -- BOUNDARY + sep * (double)(pl->pic_limit + 1) / 2.0 +
  1002. X     *                  picr * 2.0 * (double)(pl->pic_limit) / 2.0,
  1003. X     *        -- or --  PAGE_WIDTH / 2.0,
  1004. X     *
  1005. X     *        TITLE_SEP);
  1006. X     * }
  1007. X     */
  1008. X
  1009. X    fprintf(f,".PE\n");
  1010. X}
  1011. X
  1012. X
  1013. produce_pic(p, centre, picr, ptr, f)
  1014. picture *p;
  1015. char *centre;
  1016. double picr;
  1017. double ptr;
  1018. XFILE *f;
  1019. X{
  1020. X    extern double cos();
  1021. X    extern double sin();
  1022. X
  1023. X    int i;
  1024. X    static int vertex_count = 0;
  1025. X    static point *points;
  1026. X
  1027. X    /* See if there is any need to recompute the vertex coordinates. */
  1028. X
  1029. X    if (p->vertices != vertex_count){
  1030. X
  1031. X        double inc = 360.0 / (double) p->vertices; /* p->vertices != zero */
  1032. X
  1033. X        /* Need more space than there is - free the old and calloc again. */
  1034. X
  1035. X        if (p->vertices > vertex_count){ 
  1036. X            free(points);
  1037. X            if ((points = 
  1038. X                (point *)calloc(p->vertices+1, sizeof(point))) == NULL){
  1039. X                fprintf(stderr,"%s: Could not calloc! Goodbye.\n",myname);
  1040. X                goodbye();
  1041. X            }
  1042. X        }
  1043. X
  1044. X        vertex_count = p->vertices;
  1045. X
  1046. X        for (i=1; i<=p->vertices; i++){
  1047. X            double fred = (double)(i-1) * inc * RAD_ADJ;
  1048. X            points[i].x = picr * cos( fred );
  1049. X            points[i].y = picr * sin( fred );
  1050. X        }
  1051. X    }
  1052. X
  1053. X    plot_label(centre, picr, p->fig_name, p->label_width, f);
  1054. X    define_vertices(points, p->vertices, centre, ptr, f);
  1055. X    plot_vertices(p->vertices, f);
  1056. X    plot_edges(points, p->e_list, centre, f);
  1057. X}
  1058. X
  1059. X
  1060. plot_label(centre, picr, name, width, f)
  1061. char *centre;
  1062. double picr;
  1063. char *name;
  1064. double width;
  1065. XFILE *f;
  1066. X{
  1067. X    if (*name){
  1068. X        fprintf(f,"# Picture title.\n");
  1069. X        fprintf(f, "%s at %s - (%2fi, 0i)\n", name, centre,(width/2.0) + picr);
  1070. X        fprintf(f,"#\n");
  1071. X    }
  1072. X}
  1073. X
  1074. X
  1075. define_vertices(pts, n, centre, ptr, f)
  1076. point *pts;
  1077. int n;
  1078. char *centre;
  1079. double ptr;
  1080. XFILE *f;
  1081. X{
  1082. X    /*
  1083. X     * Output the defined positions of the vertices.
  1084. X     */
  1085. X
  1086. X    register int i;
  1087. X
  1088. X    fprintf(f,"# Vertice definitions.\n");
  1089. X    for (i=1; i<=n; i++){
  1090. X        fprintf(f,"define V_%d X (%.2f,%.2f) + %s X\n", i, pts[i].x, pts[i].y,
  1091. X            centre);
  1092. X    }
  1093. X    fprintf(f,"define Pt_Radius X %.2fi X\n", ptr);
  1094. X    fprintf(f,"#\n");
  1095. X}
  1096. X
  1097. X
  1098. plot_vertices(n, f)
  1099. int n;
  1100. XFILE *f;
  1101. X{
  1102. X    int i;
  1103. X
  1104. X    fprintf(f,"# Set default circle radius\n");
  1105. X    fprintf(f,"circlerad = Pt_Radius\n");
  1106. X    fprintf(f,"#\n");
  1107. X
  1108. X    fprintf(f, "# Do the vertices.\n");
  1109. X
  1110. X    for (i=1; i<=n; i++){
  1111. X
  1112. X        /* 
  1113. X         * This will produce labelled vertices from 1,2,...n - useful in debug.
  1114. X         * fprintf(f,"circle \"%d\" at V_%d\n", i, i);
  1115. X         */
  1116. X
  1117. X        fprintf(f,"circle at V_%d\n", i);
  1118. X    }
  1119. X    fprintf(f,"#\n");
  1120. X}
  1121. X
  1122. X
  1123. plot_edges(pts, edges, centre, f)
  1124. point *pts;
  1125. edge_list *edges;
  1126. char *centre;
  1127. XFILE *f;
  1128. X{
  1129. X    /* No need to check that vertex numbers are in range - done in add_edges. */
  1130. X
  1131. X    extern double get_arc_radius();
  1132. X    extern double distance();
  1133. X    char arc_radius[15];
  1134. X
  1135. X    fprintf(f,"# Draw the edges.\n");
  1136. X
  1137. X    while (edges != NULL){
  1138. X
  1139. X        int one = edges->v1;
  1140. X        int two = edges->v2;
  1141. X
  1142. X        if (edges->times != 1){
  1143. X            fprintf(f,"arcrad = %.2f\n",
  1144. X                get_arc_radius(distance(pts[one].x, pts[one].y, 
  1145. X                    pts[two].x, pts[two].y)));
  1146. X        }
  1147. X
  1148. X        /* No need to check multiplicities - done in add_edges. */
  1149. X        switch(edges->times){
  1150. X
  1151. X            case 1: {
  1152. X                fprintf(f,"line from V_%d to V_%d\n", one, two);
  1153. X                break;
  1154. X            }
  1155. X
  1156. X            case 2: {
  1157. X                fprintf(f,"arc from V_%d to V_%d\n", one, two);
  1158. X                fprintf(f,"arc from V_%d to V_%d\n", two, one);
  1159. X                break;
  1160. X            }
  1161. X
  1162. X            case 3: {
  1163. X
  1164. X                fprintf(f,"line from V_%d to V_%d\n", one, two);
  1165. X                fprintf(f,"arc from V_%d to V_%d\n", one, two);
  1166. X                fprintf(f,"arc from V_%d to V_%d\n", two, one);
  1167. X                break;
  1168. X            }
  1169. X        }
  1170. X
  1171. X        edges = edges->next_edge;
  1172. X    }
  1173. X    fprintf(f,"#\n");
  1174. X}
  1175. X
  1176. X
  1177. double
  1178. get_arc_radius(d)
  1179. double d;
  1180. X{
  1181. X        /*
  1182. X         *  Some empirical arc radius values depending on the inter pt dist.
  1183. X         *  IT'S PROBABLY NOT A GOOD IDEA TO FIDDLE WITH THESE...
  1184. X         *  of course i should now use all the least squares stuff i learned
  1185. X         *  for the comps :-)
  1186. X         */
  1187. X
  1188. X        if (d < 0.2) return(0.15);
  1189. X        if (d < 0.3) return(0.32);
  1190. X        if (d < 0.35) return(0.45);
  1191. X        if (d < 0.4) return(0.6);
  1192. X        /*if (d < 0.45) return(0.65);*/
  1193. X        if (d < 0.5) return(0.8);
  1194. X        if (d < 0.6) return(1.05);
  1195. X        if (d < 0.7) return(1.22);
  1196. X        if (d < 0.77) return(1.32);
  1197. X        if (d < 0.85) return(1.75);
  1198. X        if (d < 1.0) return(2.0);
  1199. X        if (d < 1.5) return(2.5);
  1200. X        return(3.0);
  1201. X}
  1202. X
  1203. X
  1204. double 
  1205. distance(x1, why1, x2, y2)
  1206. double x1;
  1207. double why1;
  1208. double x2;
  1209. double y2;
  1210. X{
  1211. X    return( sqrt ((x1-x2)*(x1-x2) + (why1-y2)*(why1-y2)) );
  1212. X}
  1213. X
  1214. X
  1215. char *
  1216. get_quoted_name(s)
  1217. char *s;
  1218. X{
  1219. X    /* 
  1220. X     * Try to find a quoted "" string in the array s. If one exists
  1221. X     * then return a pointer to the first quote, having zeroed the
  1222. X     * character after the closing quote.
  1223. X     */
  1224. X
  1225. X    char *start = index(s, '"');
  1226. X
  1227. X    if (start){
  1228. X        char *quotes = index(start + 1, '"');;
  1229. X        if (quotes == NULL){
  1230. X            fprintf(stderr, "Closing quote omitted on figure name. Line");
  1231. X            fprintf(stderr, " %d, file %s.\n", line_number, this_file);
  1232. X            goodbye();
  1233. X        }
  1234. X        *(quotes + 1) = '\0';
  1235. X    }
  1236. X    return(start);
  1237. X}
  1238. X
  1239. X
  1240. double
  1241. get_width(s)
  1242. char *s;
  1243. X{
  1244. X    char *quote1, *quote2;
  1245. X    double w = 0.0;
  1246. X
  1247. X    if ( (quote1 = index(s,'"')) == NULL ||
  1248. X         (quote2 = index(quote1 + 1, '"')) == NULL || 
  1249. X         sscanf(quote2 + 1, "%f", &w) != 1 )
  1250. X
  1251. X         return(0.0);
  1252. X
  1253. X    return(w);
  1254. X}
  1255. END_OF_FILE
  1256. if test 17631 -ne `wc -c <'cpic/cpic.c'`; then
  1257.     echo shar: \"'cpic/cpic.c'\" unpacked with wrong size!
  1258. fi
  1259. # end of 'cpic/cpic.c'
  1260. fi
  1261. if test -f 'cpic/cpic.h' -a "${1}" != "-c" ; then 
  1262.   echo shar: Will not clobber existing file \"'cpic/cpic.h'\"
  1263. else
  1264. echo shar: Extracting \"'cpic/cpic.h'\" \(949 characters\)
  1265. sed "s/^X//" >'cpic/cpic.h' <<'END_OF_FILE'
  1266. X/* cpic.h */
  1267. X
  1268. X#define POINT_RADIUS         0.02
  1269. X#define PIC_RADIUS           0.4
  1270. X#define PAGE_WIDTH           6.5
  1271. X#define TITLE_SEP            0.25
  1272. X#define BOUNDARY             0.2
  1273. X#define CHAR_WIDTH           0.12
  1274. X#define PIC_NAME_LIMIT       512
  1275. X#define PIC_TITLE_LIMIT      512
  1276. X
  1277. X#define RAD_ADJ ( 3.14159265 / 180.0 )
  1278. X#define MAX 1024
  1279. X
  1280. X#define GETLINE getline(in_f, MAX, line)
  1281. X#define iscomment(s) (*s == '#')
  1282. X
  1283. X
  1284. typedef struct {
  1285. X    double x;
  1286. X    double y;
  1287. X} point;
  1288. X
  1289. typedef struct edge_list_entry {
  1290. X    int v1;
  1291. X    int v2;
  1292. X    int times;
  1293. X    struct edge_list_entry *next_edge;
  1294. X} edge_list;
  1295. X
  1296. typedef struct pict {
  1297. X    int vertices;
  1298. X    char fig_name[PIC_NAME_LIMIT];
  1299. X    double label_width;
  1300. X    edge_list *e_list;
  1301. X    struct pict *next_pic;
  1302. X} picture;
  1303. X
  1304. typedef struct plist_entry {
  1305. X    int pic_limit;
  1306. X    int pics_in_list;
  1307. X    double total_label_width;
  1308. X    char pic_title[PIC_TITLE_LIMIT];
  1309. X    picture *pic;
  1310. X} picture_list;
  1311. X
  1312. X
  1313. extern char *malloc();
  1314. extern char *calloc();
  1315. extern char *index();
  1316. END_OF_FILE
  1317. if test 949 -ne `wc -c <'cpic/cpic.h'`; then
  1318.     echo shar: \"'cpic/cpic.h'\" unpacked with wrong size!
  1319. fi
  1320. # end of 'cpic/cpic.h'
  1321. fi
  1322. echo shar: End of archive 1 \(of 1\).
  1323. cp /dev/null ark1isdone
  1324. MISSING=""
  1325. for I in 1 ; do
  1326.     if test ! -f ark${I}isdone ; then
  1327.     MISSING="${MISSING} ${I}"
  1328.     fi
  1329. done
  1330. if test "${MISSING}" = "" ; then
  1331.     echo You have the archive.
  1332.     rm -f ark[1-9]isdone
  1333. else
  1334.     echo You still need to unpack the following archives:
  1335.     echo "        " ${MISSING}
  1336. fi
  1337. ##  End of shell archive.
  1338. exit 0
  1339.  
  1340.